﻿using System;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.Drawing.Text;
using System.Runtime.InteropServices;
using System.Windows.Forms;

using WEF.Standard.DevelopTools.Common.Win32;

namespace WEF.Standard.DevelopTools.Capture
{
    /// <summary>
    /// 图像处理控件，支持选区与遮罩绘制，提供高性能绘制优化
    /// </summary>
    public partial class ImageProcessBox : Control
    {
        /// <summary>
        /// 初始化控件，启用双缓冲与样式以减少闪烁
        /// </summary>
        public ImageProcessBox()
        {
            InitializeComponent();
            InitMember();

            this.ForeColor = Color.White;
            this.BackColor = Color.Black;
            this.Dock = DockStyle.Fill;

            this.SetStyle(ControlStyles.ResizeRedraw, true);
            this.SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
            this.SetStyle(ControlStyles.AllPaintingInWmPaint, true);
            this.SetStyle(ControlStyles.UserPaint, true);
            this.SetStyle(ControlStyles.SupportsTransparentBackColor, true);
            this.UpdateStyles();
        }

        private void InitMember()
        {
            this.dotColor = Color.FromArgb(255, 0, 255, 255);
            this.lineColor = Color.FromArgb(255, 0, 255, 255);
            this.magnifySize = new Size(20, 20);
            this.magnifyTimes = 9;
            this.isDrawOperationDot = true;
            this.isSetClip = false;  // 修复跨屏幕问题：禁用裁剪限制
            this.isShowInfo = true;
            this.autoSizeFromImage = true;
            this.canReset = true;
            m_pen = new Pen(lineColor, 1);
            m_sb = new SolidBrush(dotColor);
            this.Font = new Font("微软雅黑", 8);
            this.selectedRectangle = new Rectangle();
            this.ClearDraw();
            m_rectDots = new Rectangle[8];
            for (int i = 0; i < 8; i++)
            {
                m_rectDots[i] = new Rectangle(-10, -10, 15, 15);
            }
        }

        ~ImageProcessBox()
        {
            m_pen.Dispose();
            m_sb.Dispose();
            if (this.baseImage != null)
            {
                m_bmpDark.Dispose();
                this.baseImage.Dispose();
            }
        }

        public void DeleResource()
        {
            m_pen.Dispose();
            m_sb.Dispose();
            if (this.baseImage != null)
            {
                m_bmpDark.Dispose();
                this.baseImage.Dispose();
            }
        }

        #region Properties

        private Image baseImage;
        /// <summary>
        /// 获取或设置用于被操作的图像
        /// </summary>
        [Category("Custom"), Description("获取或设置用于被操作的图像")]
        public Image WorkImage
        {
            get { return baseImage; }
            set
            {
                baseImage = value;
                this.DrawImage();
            }
        }

        private Color dotColor;
        /// <summary>
        /// 获取或设置操作框点的颜色
        /// </summary>
        [Description("获取或设置操作框点的颜色")]
        [DefaultValue(typeof(Color), "Yellow"), Category("Custom")]
        public Color DotColor
        {
            get { return dotColor; }
            set { dotColor = value; }
        }

        private Color lineColor;
        /// <summary>
        /// 获取或设置操作框线条的颜色
        /// </summary>
        [Description("获取或设置操作框线条的颜色")]
        [DefaultValue(typeof(Color), "Cyan"), Category("Custom")]
        public Color LineColor
        {
            get { return lineColor; }
            set { lineColor = value; }
        }

        private Rectangle selectedRectangle;
        /// <summary>
        /// 获取当前选中的区域
        /// </summary>
        [Browsable(false)]
        public Rectangle SelectedRectangle
        {
            get
            {
                Rectangle rectTemp = selectedRectangle;
                rectTemp.Width++; rectTemp.Height++;
                return rectTemp;
            }
        }

        private Size magnifySize;
        /// <summary>
        /// 获取或设置放大图像的原图大小尺寸
        /// </summary>
        [Description("获取或设置放大图像的原图大小尺寸")]
        [DefaultValue(typeof(Size), "20,20"), Category("Custom")]
        public Size MagnifySize
        {
            get { return magnifySize; }
            set
            {
                magnifySize = value;
                if (magnifySize.Width < 5) magnifySize.Width = 5;
                if (magnifySize.Width > 20) magnifySize.Width = 20;
                if (magnifySize.Height < 5) magnifySize.Height = 5;
                if (magnifySize.Height > 20) magnifySize.Height = 20;
            }
        }

        private int magnifyTimes;
        /// <summary>
        /// 获取或设置图像放大的倍数
        /// </summary>
        [Description("获取或设置图像放大的倍数")]
        [DefaultValue(10), Category("Custom")]
        public int MagnifyTimes
        {
            get { return magnifyTimes; }
            set
            {
                magnifyTimes = value;
                if (magnifyTimes < 3) magnifyTimes = 3;
                if (magnifyTimes > 10) magnifyTimes = 10;
            }
        }

        private bool isDrawOperationDot;
        /// <summary>
        /// 获取或设置是否绘制操作框点
        /// </summary>
        [Description("获取或设置是否绘制操作框点")]
        [DefaultValue(true), Category("Custom")]
        public bool IsDrawOperationDot
        {
            get { return isDrawOperationDot; }
            set
            {
                if (value == isDrawOperationDot) return;
                isDrawOperationDot = value;
                this.Invalidate();
            }
        }

        private bool isSetClip;
        /// <summary>
        /// 获取或设置是否限制鼠标操作区域
        /// </summary>
        [Description("获取或设置是否限制鼠标操作区域")]
        [DefaultValue(true), Category("Custom")]
        public bool IsSetClip
        {
            get { return isSetClip; }
            set { isSetClip = value; }
        }

        private bool isShowInfo;
        /// <summary>
        /// 获取或设置是否绘制信息展示
        /// </summary>
        [Description("获取或设置是否绘制信息展示")]
        [DefaultValue(true), Category("Custom")]
        public bool IsShowInfo
        {
            get { return isShowInfo; }
            set { isShowInfo = value; }
        }

        private bool autoSizeFromImage;
        /// <summary>
        /// 获取或设置是否根据图像大小自动调整控件尺寸
        /// </summary>
        [Description("获取或设置是否根据图像大小自动调整控件尺寸")]
        [DefaultValue(true), Category("Custom")]
        public bool AutoSizeFromImage
        {
            get { return autoSizeFromImage; }
            set
            {
                if (value && this.baseImage != null)
                {
                    this.Width = this.baseImage.Width;
                    this.Height = this.baseImage.Height;
                }
                autoSizeFromImage = value;
            }
        }

        private bool isDrawed;
        /// <summary>
        /// 获取当前是否绘制的有区域
        /// </summary>
        [Browsable(false)]
        public bool IsDrawed
        {
            get { return isDrawed; }
        }

        private bool isStartDraw;
        /// <summary>
        /// 获取当前是否开始绘制
        /// </summary>
        [Browsable(false)]
        public bool IsStartDraw
        {
            get { return isStartDraw; }
        }

        private bool isMoving;
        /// <summary>
        /// 获取当前操作框是否正在移动
        /// </summary>
        [Browsable(false)]
        public bool IsMoving
        {
            get { return isMoving; }
        }

        private bool canReset;
        /// <summary>
        /// 获取或设置操作框是否锁定
        /// </summary>
        [Browsable(false)]
        public bool CanReset
        {
            get { return canReset; }
            set
            {
                canReset = value;
                if (!canReset) this.Cursor = Cursors.Default;
            }
        }


        public Rectangle VirtualScreenBounds
        {
            get; set;
        }

        #endregion

        #region Member variable

        private bool m_bMouseEnter;
        private bool m_bLockH;
        private bool m_bLockW;
        private Point m_ptOriginal;
        private Point m_ptCurrent;
        private Point m_ptTempStarPos;
        private Rectangle[] m_rectDots;
        private Rectangle m_rectClip;

        private Bitmap m_bmpDark;
        private Pen m_pen;
        private SolidBrush m_sb;

        #endregion

        /// <summary>
        /// 鼠标按下开始绘制或移动选区，设置光标限制区域
        /// </summary>
        protected override void OnMouseDown(MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Left)
            {
                //根据情况是否开始绘制操作框
                if (!this.IsDrawed || this.Cursor != Cursors.Default)
                {
                    m_rectClip = this.DisplayRectangle;
                    if (this.baseImage != null)
                    {
                        if (this.isSetClip)
                        {
                            if (e.X > this.baseImage.Width || e.Y > this.baseImage.Height) return;
                            m_rectClip.Intersect(new Rectangle(0, 0, this.baseImage.Width, this.baseImage.Height));
                        }
                        else
                        {
                            // 修复跨屏幕问题：使用整个图像区域作为操作区域
                            m_rectClip = new Rectangle(0, 0, this.baseImage.Width, this.baseImage.Height);
                        }
                    }
                    // 修复多屏环境下鼠标乱跳问题：使用更安全的坐标计算
                    try
                    {
                        // 使用 ScreenHelper 进行客户端矩形到屏幕坐标转换，兼容多屏/DPI
                        var clipRect = ScreenHelper.ClientRectToScreen(this, m_rectClip);
                        if (clipRect.Width > 0 && clipRect.Height > 0)
                        {
                            // 限制光标活动区域，防止跨屏拖动越界
                            Cursor.Clip = clipRect;
                        }
                    }
                    catch (Exception ex)
                    {
                        System.Diagnostics.Debug.WriteLine($"设置Cursor.Clip失败: {ex.Message}");
                    }
                    isStartDraw = true;
                    m_ptOriginal = e.Location;
                }
            }
            this.Focus();
            base.OnMouseDown(e);
        }

        /// <summary>
        /// 鼠标移动处理：移动或缩放选区，并进行局部失效刷新（含节流）
        /// </summary>
        protected override void OnMouseMove(MouseEventArgs e)
        {
            m_ptCurrent = e.Location;
            m_bMouseEnter = true;

            #region Process OperationBox

            if (isDrawed && this.canReset)
            {
                //如果已经绘制 并且可以操作选区 判断操作类型
                this.SetCursorStyle(e.Location);
                if (isStartDraw && this.isDrawOperationDot)
                {
                    if (m_rectDots[0].Contains(e.Location))
                    {
                        isDrawed = false;
                        m_ptOriginal.X = this.selectedRectangle.Right;
                        m_ptOriginal.Y = this.selectedRectangle.Bottom;
                    }
                    else if (m_rectDots[1].Contains(e.Location))
                    {
                        isDrawed = false;
                        m_ptOriginal.Y = this.selectedRectangle.Bottom;
                        m_bLockW = true;
                    }
                    else if (m_rectDots[2].Contains(e.Location))
                    {
                        isDrawed = false;
                        m_ptOriginal.X = this.selectedRectangle.X;
                        m_ptOriginal.Y = this.selectedRectangle.Bottom;
                    }
                    else if (m_rectDots[3].Contains(e.Location))
                    {
                        isDrawed = false;
                        m_ptOriginal.X = this.selectedRectangle.Right;
                        m_bLockH = true;
                    }
                    else if (m_rectDots[4].Contains(e.Location))
                    {
                        isDrawed = false;
                        m_ptOriginal.X = this.selectedRectangle.X;
                        m_bLockH = true;
                    }
                    else if (m_rectDots[5].Contains(e.Location))
                    {
                        isDrawed = false;
                        m_ptOriginal.X = this.selectedRectangle.Right;
                        m_ptOriginal.Y = this.selectedRectangle.Y;
                    }
                    else if (m_rectDots[6].Contains(e.Location))
                    {
                        isDrawed = false;
                        m_ptOriginal.Y = this.selectedRectangle.Y;
                        m_bLockW = true;
                    }
                    else if (m_rectDots[7].Contains(e.Location))
                    {
                        isDrawed = false;
                        m_ptOriginal = this.selectedRectangle.Location;
                    }
                    else if (this.selectedRectangle.Contains(e.Location))
                    {
                        isDrawed = false;
                        isMoving = true;
                    }
                }
                base.OnMouseMove(e);
                return;
            }

            #endregion

            #region Calculate the operationbox

            if (isStartDraw)
            {
                if (isMoving)
                {
                    //如果移动选区 只重置 location
                    var oldRect = this.selectedRectangle;
                    this.selectedRectangle.X = m_ptTempStarPos.X + e.X - m_ptOriginal.X;
                    this.selectedRectangle.Y = m_ptTempStarPos.Y + e.Y - m_ptOriginal.Y;

                    // 修复跨屏幕问题：使用整个图像区域作为边界
                    if (this.selectedRectangle.X < 0) this.selectedRectangle.X = 0;
                    if (this.selectedRectangle.Y < 0) this.selectedRectangle.Y = 0;
                    if (this.selectedRectangle.Right > m_rectClip.Width)
                        this.selectedRectangle.X = m_rectClip.Width - this.selectedRectangle.Width - 1;
                    if (this.selectedRectangle.Bottom > m_rectClip.Height)
                        this.selectedRectangle.Y = m_rectClip.Height - this.selectedRectangle.Height - 1;

                    // 合并旧/新选区并执行局部失效刷新（含节流）
                    // 合并旧/新选区并执行局部失效刷新（含节流）
                    InvalidateSelectionChange(oldRect, this.selectedRectangle);
                }
                else
                {
                    // 重置大小
                    var oldRect = this.selectedRectangle;
                    selectedRectangle.X = m_ptOriginal.X - e.X < 0 ? m_ptOriginal.X : e.X;
                    selectedRectangle.Width = Math.Abs(m_ptOriginal.X - e.X);
                    if (!m_bLockW)
                    {
                        selectedRectangle.Y = m_ptOriginal.Y - e.Y < 0 ? m_ptOriginal.Y : e.Y;
                        selectedRectangle.Height = Math.Abs(m_ptOriginal.Y - e.Y);
                    }
                    InvalidateSelectionChange(oldRect, this.selectedRectangle);
                }
            }

            #endregion
            //绘制放大信息
            if (this.baseImage != null && !isDrawed && !isMoving && isShowInfo)
                this.Invalidate();
            base.OnMouseMove(e);
        }

        protected override void OnMouseLeave(EventArgs e)
        {
            m_bMouseEnter = false;
            this.Invalidate();
            base.OnMouseLeave(e);
        }

        protected override void OnMouseUp(MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Left)
            {
                //如果绘制太小 则视为无效
                if (this.selectedRectangle.Width >= 4 && this.selectedRectangle.Height >= 4)
                    isDrawed = true;
                else
                    this.ClearDraw();
                isMoving = m_bLockH = m_bLockW = false; //取消锁定
                isStartDraw = false;
                m_ptTempStarPos = this.selectedRectangle.Location;
                // 安全地清理Cursor.Clip，避免多屏环境下的问题
                try
                {
                    Cursor.Clip = new Rectangle();
                }
                catch (Exception ex)
                {
                    System.Diagnostics.Debug.WriteLine($"清理Cursor.Clip失败: {ex.Message}");
                }
            }
            else if (e.Button == MouseButtons.Right)
                this.ClearDraw();
            this.Invalidate();
            base.OnMouseUp(e);
        }

        //响应四个按键实现精确移动
        protected override void OnKeyPress(KeyPressEventArgs e)
        {
            if (e.KeyChar == 'w')
                MouseAndKeyHelper.SetCursorPos(MousePosition.X, MousePosition.Y - 1);
            else if (e.KeyChar == 's')
                MouseAndKeyHelper.SetCursorPos(MousePosition.X, MousePosition.Y + 1);
            else if (e.KeyChar == 'a')
                MouseAndKeyHelper.SetCursorPos(MousePosition.X - 1, MousePosition.Y);
            else if (e.KeyChar == 'd')
                MouseAndKeyHelper.SetCursorPos(MousePosition.X + 1, MousePosition.Y);
            base.OnKeyPress(e);
        }

        /// <summary>
        /// 背景绘制策略：仅在无底图时绘制背景，避免重复背景涂刷造成闪烁
        /// </summary>
        protected override void OnPaintBackground(PaintEventArgs pevent)
        {
            // 减少闪烁：在绘制基图时跳过背景涂刷，仅在无图像时绘制背景
            if (this.baseImage == null)
            {
                base.OnPaintBackground(pevent);
            }
            // 否则不绘制背景，由 OnPaint 完整覆盖
        }

        /// <summary>
        /// 重写控件的绘制图像
        /// </summary>
        /// <param name="e"></param>
        /// <summary>
        /// 主绘制流程：遮罩与选区内容绘制，并按拖拽状态切换绘制质量
        /// </summary>
        protected override void OnPaint(PaintEventArgs e)
        {
            Graphics g = e.Graphics;

            if (this.baseImage != null)
            {
                // 根据拖拽/移动状态切换绘制质量：拖拽用高速，静止用高质量
                // 拖拽/移动中：采用高速绘制参数，提升帧率
                if (isMoving || isStartDraw)
                {
                    g.CompositingQuality = CompositingQuality.HighSpeed;
                    g.InterpolationMode = InterpolationMode.NearestNeighbor;
                    g.PixelOffsetMode = PixelOffsetMode.None;
                    g.SmoothingMode = SmoothingMode.None;
                }
                else
                {
                    // 静止状态：采用高质量绘制参数，提升显示效果
                    g.CompositingQuality = CompositingQuality.HighQuality;
                    g.InterpolationMode = InterpolationMode.NearestNeighbor;
                    g.PixelOffsetMode = PixelOffsetMode.Half;
                    g.SmoothingMode = SmoothingMode.None;
                    g.TextRenderingHint = TextRenderingHint.ClearTypeGridFit;
                }

                // 绘制带半透明遮罩的整个图像（仅绘制无效区域）
                var clip = e.ClipRectangle;
                // 使用 SourceCopy 进行遮罩覆盖，降低混合成本
                g.CompositingMode = CompositingMode.SourceCopy;
                if (!clip.IsEmpty)
                    g.DrawImage(m_bmpDark, clip, clip, GraphicsUnit.Pixel);
                else
                    g.DrawImage(m_bmpDark, 0, 0, m_bmpDark.Width, m_bmpDark.Height);
                // 恢复默认的 SourceOver 混合模式，用于后续正常绘制
                g.CompositingMode = CompositingMode.SourceOver;

                // 绘制选取框内的原始清晰图像
                if (this.selectedRectangle.Width > 0 && this.selectedRectangle.Height > 0 &&
                    this.baseImage != null &&
                    this.selectedRectangle.X >= 0 && this.selectedRectangle.Y >= 0 &&
                    this.selectedRectangle.Right <= this.baseImage.Width &&
                    this.selectedRectangle.Bottom <= this.baseImage.Height)
                {
                    g.DrawImage(this.baseImage, this.selectedRectangle, this.selectedRectangle, GraphicsUnit.Pixel);
                }
            }
            this.DrawOperationBox(g);
            if (this.baseImage != null && e != null && e.Graphics != null && !isDrawed && !isMoving && m_bMouseEnter && isShowInfo)
            {
                DrawMagnifyInfo(e.Graphics);
            }
            base.OnPaint(e);
        }
        /// <summary>
        /// 绘制操作框
        /// </summary>
        /// <param name="g"></param>
        /// <summary>
        /// 绘制操作框（控制点与尺寸信息），无选区时跳过绘制
        /// </summary>
        protected virtual void DrawOperationBox(Graphics g)
        {
            if (this.selectedRectangle.Width <= 0 || this.selectedRectangle.Height <= 0) return;

            #region Draw SizeInfo

            if (!isMoving && !isStartDraw)
            {
                string strDrawSize = "X:" + this.selectedRectangle.X + " Y:" + this.selectedRectangle.Y +
                    " W:" + (this.selectedRectangle.Width + 1) + " H:" + (this.selectedRectangle.Height + 1);
                Size seStr = TextRenderer.MeasureText(strDrawSize, this.Font);
                int tempX = this.selectedRectangle.X;
                int tempY = this.selectedRectangle.Y - seStr.Height - 5;
                if (!m_rectClip.IsEmpty)
                    if (tempX + seStr.Width >= m_rectClip.Right) tempX -= seStr.Width;
                if (tempY <= 0) tempY += seStr.Height + 10;

                m_sb.Color = Color.FromArgb(125, 0, 0, 0);
                g.FillRectangle(m_sb, tempX, tempY, seStr.Width, seStr.Height);
                m_sb.Color = this.ForeColor;
                g.DrawString(strDrawSize, this.Font, m_sb, tempX, tempY);
            }

            #endregion

            if (!this.isDrawOperationDot)
            {
                m_pen.Width = 3; m_pen.Color = this.lineColor;
                g.DrawRectangle(m_pen, this.selectedRectangle);
                return;
            }
            //计算八个顶点位置 - 优化：将所有控制点移到选择框线内，避免选择失败
            const int dotSize = 15;
            const int margin = 2;

            // 控制点布局说明：
            // [0]左上角  [1]上中  [2]右上角
            // [3]左中              [4]右中
            // [5]左下角  [6]下中  [7]右下角

            // 上边三个点：移到框内顶部
            m_rectDots[0].Y = m_rectDots[1].Y = m_rectDots[2].Y = this.selectedRectangle.Y + margin;
            // 下边三个点：移到框内底部（边界检查）
            int bottomY = this.selectedRectangle.Height > dotSize + margin * 2
                ? this.selectedRectangle.Bottom - dotSize - margin
                : this.selectedRectangle.Y + margin;
            m_rectDots[5].Y = m_rectDots[6].Y = m_rectDots[7].Y = bottomY;
            // 左边三个点：移到框内左侧
            m_rectDots[0].X = m_rectDots[3].X = m_rectDots[5].X = this.selectedRectangle.X + margin;
            // 右边三个点：移到框内右侧（边界检查）
            int rightX = this.selectedRectangle.Width > dotSize + margin * 2
                ? this.selectedRectangle.Right - dotSize - margin
                : this.selectedRectangle.X + margin;
            m_rectDots[2].X = m_rectDots[4].X = m_rectDots[7].X = rightX;

            // 中间左右两个点：垂直居中
            int centerY = this.selectedRectangle.Y + this.selectedRectangle.Height / 2 - dotSize / 2;
            m_rectDots[3].Y = m_rectDots[4].Y = centerY;

            // 中间上下两个点：水平居中
            int centerX = this.selectedRectangle.X + this.selectedRectangle.Width / 2 - dotSize / 2;
            m_rectDots[1].X = m_rectDots[6].X = centerX;
            m_pen.Width = 1; m_pen.Color = this.lineColor;
            g.DrawRectangle(m_pen, this.selectedRectangle);
            m_sb.Color = this.dotColor;
            foreach (Rectangle rect in m_rectDots)
            {
                g.FillRectangle(m_sb, rect);
            }
            if (this.selectedRectangle.Width <= 10 || this.selectedRectangle.Height <= 10)
                g.DrawRectangle(m_pen, this.selectedRectangle);
        }
        /// <summary>
        /// 绘制图像放大信息
        /// </summary>
        /// <param name="g"></param>
        protected virtual void DrawMagnifyInfo(Graphics g)
        {
            #region Calculate point

            int tempX = (m_ptCurrent.X > this.ClientRectangle.Width - 2 ? this.ClientRectangle.Width - 2 : m_ptCurrent.X) + 20;
            int tempY = m_ptCurrent.Y + 20;
            int tempW = this.magnifySize.Width * this.magnifyTimes + 8;
            int tempH = this.magnifySize.Width * this.magnifyTimes + 12 + this.Font.Height * 3;
            if (!m_rectClip.IsEmpty)
            {
                if (tempX + tempW >= this.m_rectClip.Right) tempX -= tempW + 30;
                if (tempY + tempH >= this.m_rectClip.Bottom) tempY -= tempH + 30;
            }
            else
            {
                if (tempX + tempW >= this.ClientRectangle.Width - 2) tempX -= tempW + 30;
                if (tempY + tempH >= this.ClientRectangle.Height) tempY -= tempH + 30;
            }
            Rectangle tempRectBorder = new Rectangle(tempX + 2, tempY + 2, tempW - 4, this.magnifySize.Width * this.magnifyTimes + 4);

            #endregion

            m_sb.Color = Color.FromArgb(200, 0, 0, 0);
            g.FillRectangle(m_sb, tempX, tempY, tempW, tempH);
            m_pen.Width = 1;
            m_pen.Color = Color.White;
            g.DrawRectangle(m_pen, tempRectBorder);

            #region Draw the magnified image

            using (Bitmap bmpSrc = new Bitmap(this.magnifySize.Width, this.magnifySize.Height, PixelFormat.Format32bppArgb))
            {
                using (Graphics gp = Graphics.FromImage(bmpSrc))
                {
                    gp.DrawImage(this.baseImage, -(m_ptCurrent.X - this.magnifySize.Width / 2), -(m_ptCurrent.Y - this.magnifySize.Height / 2));
                }
                using (Bitmap bmpInfo = ImageProcessBox.MagnifyImage(bmpSrc, this.magnifyTimes))
                {
                    g.DrawImage(bmpInfo, tempX + 4, tempY + 4);
                }
            }

            #endregion

            m_pen.Width = this.magnifyTimes - 2;
            m_pen.Color = Color.FromArgb(125, 0, 255, 255);
            int tempCenterX = tempX + (tempW + (this.magnifySize.Width % 2 == 0 ? this.magnifyTimes : 0)) / 2;
            int tempCenterY = tempY + 2 + (tempRectBorder.Height + (this.MagnifySize.Height % 2 == 0 ? this.magnifyTimes : 0)) / 2;
            g.DrawLine(m_pen, tempCenterX, tempY + 4, tempCenterX, tempRectBorder.Bottom - 2);
            g.DrawLine(m_pen, tempX + 4, tempCenterY, tempX + tempW - 4, tempCenterY);

            #region Draw Info

            m_sb.Color = this.ForeColor;
            Color clr = ((Bitmap)this.baseImage).GetPixel((m_ptCurrent.X >= this.ClientRectangle.Width - 2 ? this.ClientRectangle.Width - 2 : m_ptCurrent.X), m_ptCurrent.Y);
            g.DrawString($"尺寸:{this.selectedRectangle.Width + 1} x {this.selectedRectangle.Height + 1}",
                this.Font, m_sb, tempX + 2, tempRectBorder.Bottom + 2);
            g.DrawString($"颜色: #{clr.R.ToString("X").PadLeft(2, '0')}{clr.G.ToString("X").PadLeft(2, '0')}{clr.B.ToString("X").PadLeft(2, '0')}",
                this.Font, m_sb, tempX + 2, tempRectBorder.Bottom + 2 + this.Font.Height);
            g.DrawString($"Ctrl+C 复制", this.Font, m_sb, tempX + 2, tempRectBorder.Bottom + 2 + this.Font.Height * 2);
            m_sb.Color = clr;
            g.FillRectangle(m_sb, tempX + tempW - 2 - this.Font.Height,         //右下角颜色
                tempY + tempH - 2 - this.Font.Height,
                this.Font.Height,
                this.Font.Height);
            g.DrawRectangle(Pens.Cyan, tempX + tempW - 2 - this.Font.Height,    //右下角颜色边框
                tempY + tempH - 2 - this.Font.Height,
                this.Font.Height,
                this.Font.Height);
            g.FillRectangle(m_sb, tempCenterX - this.magnifyTimes / 2,          //十字架中间颜色
                tempCenterY - this.magnifyTimes / 2,
                this.magnifyTimes,
                this.magnifyTimes);
            g.DrawRectangle(Pens.Cyan, tempCenterX - this.magnifyTimes / 2,     //十字架中间边框
                tempCenterY - this.magnifyTimes / 2,
                this.magnifyTimes - 1,
                this.magnifyTimes - 1);

            #endregion
        }
        //放大图形
        private static Bitmap MagnifyImage(Bitmap bmpSrc, int times)
        {
            Bitmap bmpNew = new Bitmap(bmpSrc.Width * times, bmpSrc.Height * times, PixelFormat.Format32bppArgb);
            BitmapData bmpSrcData = bmpSrc.LockBits(new Rectangle(0, 0, bmpSrc.Width, bmpSrc.Height), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
            BitmapData bmpNewData = bmpNew.LockBits(new Rectangle(0, 0, bmpNew.Width, bmpNew.Height), ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb);
            byte[] bySrcData = new byte[bmpSrcData.Height * bmpSrcData.Stride];
            Marshal.Copy(bmpSrcData.Scan0, bySrcData, 0, bySrcData.Length);
            byte[] byNewData = new byte[bmpNewData.Height * bmpNewData.Stride];
            Marshal.Copy(bmpNewData.Scan0, byNewData, 0, byNewData.Length);
            for (int y = 0, lenY = bmpSrc.Height; y < lenY; y++)
            {
                for (int x = 0, lenX = bmpSrc.Width; x < lenX; x++)
                {
                    for (int cy = 0; cy < times; cy++)
                    {
                        for (int cx = 0; cx < times; cx++)
                        {
                            byNewData[(x * times + cx) * 4 + ((y * times + cy) * bmpNewData.Stride)] = bySrcData[x * 4 + y * bmpSrcData.Stride];
                            byNewData[(x * times + cx) * 4 + ((y * times + cy) * bmpNewData.Stride) + 1] = bySrcData[x * 4 + y * bmpSrcData.Stride + 1];
                            byNewData[(x * times + cx) * 4 + ((y * times + cy) * bmpNewData.Stride) + 2] = bySrcData[x * 4 + y * bmpSrcData.Stride + 2];
                            byNewData[(x * times + cx) * 4 + ((y * times + cy) * bmpNewData.Stride) + 3] = bySrcData[x * 4 + y * bmpSrcData.Stride + 3];
                        }
                    }
                }
            }
            Marshal.Copy(byNewData, 0, bmpNewData.Scan0, byNewData.Length);
            bmpSrc.UnlockBits(bmpSrcData);
            bmpNew.UnlockBits(bmpNewData);
            return bmpNew;
        }
        //设置鼠标指针样式
        private void SetCursorStyle(Point loc)
        {
            if (m_rectDots[0].Contains(loc) || m_rectDots[7].Contains(loc))
                this.Cursor = Cursors.SizeNWSE;
            else if (m_rectDots[1].Contains(loc) || m_rectDots[6].Contains(loc))
                this.Cursor = Cursors.SizeNS;
            else if (m_rectDots[2].Contains(loc) || m_rectDots[5].Contains(loc))
                this.Cursor = Cursors.SizeNESW;
            else if (m_rectDots[3].Contains(loc) || m_rectDots[4].Contains(loc))
                this.Cursor = Cursors.SizeWE;
            else if (this.selectedRectangle.Contains(loc) /*&& this.canReset*/)
                this.Cursor = Cursors.SizeAll;
            else
                this.Cursor = Cursors.Default;
        }

        /// <summary>
        /// 将屏幕截图绘制到控件上，并增加一个半透明的遮罩
        /// </summary>
        private void DrawImage()
        {
            if (this.baseImage == null) return;

            try
            {
                m_bmpDark = new Bitmap(this.baseImage);
                using (Graphics g = Graphics.FromImage(m_bmpDark))
                {
                    g.SmoothingMode = SmoothingMode.HighSpeed;
                    g.InterpolationMode = InterpolationMode.NearestNeighbor;
                    g.PixelOffsetMode = PixelOffsetMode.None;
                    g.CompositingQuality = CompositingQuality.HighSpeed;

                    using (SolidBrush sb = new SolidBrush(Color.FromArgb(150, 0, 0, 0)))
                    {
                        g.FillRectangle(sb, 0, 0, m_bmpDark.Width, m_bmpDark.Height);
                    }
                }
            }
            catch (Exception ex)
            {
                System.Diagnostics.Debug.WriteLine($"DrawImage失败: {ex.Message}");
                m_bmpDark?.Dispose();
                m_bmpDark = null;
            }
        }
        /// <summary>
        /// 清空所有操作
        /// </summary>
        public void ClearDraw()
        {
            isDrawed = false;
            this.selectedRectangle.X = this.selectedRectangle.Y = -100;
            this.selectedRectangle.Width = this.selectedRectangle.Height = 0;
            this.Cursor = Cursors.Default;
            this.Invalidate();
        }
        /// <summary>
        /// 手动设置一个块选中区域
        /// </summary>
        /// <param name="rect">要选中区域</param>
        public void SetSelectRect(Rectangle rect)
        {
            rect.Intersect(this.DisplayRectangle);
            if (rect.IsEmpty) return;
            rect.Width--; rect.Height--;
            if (this.selectedRectangle == rect) return;
            this.selectedRectangle = rect;
            this.Invalidate();
        }
        /// <summary>
        /// 手动设置一个块选中区域
        /// </summary>
        /// <param name="pt">要选中区域的坐标</param>
        /// <param name="se">要选中区域的大小</param>
        public void SetSelectRect(Point pt, Size se)
        {
            Rectangle rectTemp = new Rectangle(pt, se);
            rectTemp.Intersect(this.DisplayRectangle);
            if (rectTemp.IsEmpty) return;
            rectTemp.Width--; rectTemp.Height--;
            if (this.selectedRectangle == rectTemp) return;
            this.selectedRectangle = rectTemp;
            this.Invalidate();
        }
        /// <summary>
        /// 手动设置一个块选中区域
        /// </summary>
        /// <param name="x">要选中区域的x坐标</param>
        /// <param name="y">要选中区域的y坐标</param>
        /// <param name="w">要选中区域的宽度</param>
        /// <param name="h">要选中区域的高度</param>
        public void SetSelectRect(int x, int y, int w, int h)
        {
            Rectangle rectTemp = new Rectangle(x, y, w, h);
            rectTemp.Intersect(this.DisplayRectangle);
            if (rectTemp.IsEmpty) return;
            rectTemp.Width--; rectTemp.Height--;
            if (this.selectedRectangle == rectTemp) return;
            this.selectedRectangle = rectTemp;
            this.Invalidate();
        }
        /// <summary>
        /// 手动设置信息显示的位置
        /// </summary>
        /// <param name="pt">要显示的位置</param>
        public void SetInfoPoint(Point pt)
        {
            if (m_ptCurrent == pt) return;
            m_ptCurrent = pt;
            m_bMouseEnter = true;
            this.Invalidate();
        }
        /// <summary>
        /// 手动设置信息显示的位置
        /// </summary>
        /// <param name="x">要显示位置的x坐标</param>
        /// <param name="y">要显示位置的y坐标</param>
        public void SetInfoPoint(int x, int y)
        {
            if (m_ptCurrent.X == x && m_ptCurrent.Y == y) return;
            m_ptCurrent.X = x;
            m_ptCurrent.Y = y;
            m_bMouseEnter = true;
            this.Invalidate();
        }
        /// <summary>
        /// 获取操作框内的图像
        /// </summary>
        /// <returns>结果图像</returns>
        public Bitmap GetResultBmp()
        {
            if (this.baseImage == null) return null;
            Bitmap bmp = new Bitmap(this.selectedRectangle.Width + 1, this.selectedRectangle.Height + 1);
            using (Graphics g = Graphics.FromImage(bmp))
            {
                g.CompositingQuality = CompositingQuality.HighQuality;
                g.InterpolationMode = InterpolationMode.NearestNeighbor;
                g.PixelOffsetMode = PixelOffsetMode.Half;
                g.SmoothingMode = SmoothingMode.None;
                g.TextRenderingHint = System.Drawing.Text.TextRenderingHint.ClearTypeGridFit;

                g.DrawImage(this.baseImage, -this.selectedRectangle.X, -this.selectedRectangle.Y);
            }
            return bmp;
        }



        private long _lastInvalidateTick; // 最近一次局部失效的时间戳（毫秒）
        private const int InvalidateMinIntervalMs = 8; // 局部失效的最小间隔，避免高频重绘

        /// <summary>
        /// 根据选区变化进行最小化失效并节流，减少重复重绘
        /// </summary>
        private void InvalidateSelectionChange(Rectangle oldRect, Rectangle newRect)
        {
            if (oldRect == newRect) return; // 无变化直接跳过
            var r = Rectangle.Union(oldRect, newRect); // 合并旧/新区域，得到最小刷新区域
            r.Inflate(2, 2); // 适度扩大，避免边缘残影
            var now = Environment.TickCount; // 当前时间戳（毫秒）
            if (now - _lastInvalidateTick < InvalidateMinIntervalMs) return; // 节流：小于最小间隔则跳过
            _lastInvalidateTick = now; // 更新最后一次失效时间戳
            this.Invalidate(r); // 仅对必要区域进行局部刷新
        }

    }

}